﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Timers;


namespace NIP.Speech.Dialog
{
    public class Responder
    {

        //! Timer

        const int MAX_TIME = 5000;
        const int INVERVAL = 100;
        Timer Clock;
        int count = MAX_TIME / INVERVAL;


        private Microsoft.Speech.Synthesis.SpeechSynthesizer synthesisEngine;
        private System.Speech.Synthesis.SpeechSynthesizer sysSpeak;
        
        private IDialogState _curState;
        static public StateStatus responderStatus;

        public event EventHandler<System.EventArgs> StateInitiated;
        public event EventHandler<System.EventArgs> StateCompleted;
        public event EventHandler<EventArgs.StateStatusEventArgs> StateStatusChanged;
        public event EventHandler<EventArgs.SpeechActionRequestedEventArgs> SpeechActionRequested;
        public Responder()
        {
            synthesisEngine = new Microsoft.Speech.Synthesis.SpeechSynthesizer();
            sysSpeak = new System.Speech.Synthesis.SpeechSynthesizer();
            sysSpeak.Rate = 0;
            _curState = new States.IdleDialogState();
            
            Clock = new Timer();
            Clock.Interval = 100;
            Clock.Start();
            Clock.Elapsed += new ElapsedEventHandler(Timer_Tick); 
        }

        public void InitState()
        {
            Clock.Stop();
            //! All match
            _curState.IsReady = true;
            if (_curState.para != null)
            {
                if (_curState.para.inputCommand.Count > 0)
                {
                    StateStatusArgs_Resolver(_curState.VoiceCommandResponse(_curState.para.inputCommand));
                }
            }
            if (StateInitiated != null)
            {
                StateInitiated(_curState, new System.EventArgs());
            }
            
            System.Diagnostics.Debug.WriteLine("Init");
        }

        public void Timer_Tick(object sender, System.Timers.ElapsedEventArgs eArgs)
        {
            //! Condition matching
            if (_curState.PreConditionCheck())
            {
                InitState();
            }
            else
            {
                if (count-- <= 0)
                {
                    //! Time out -- aborting
                    MoveToNextState(_curState.DefaultAbortNextState);
                }
            }
        }

        /// <summary>
        /// To be called by StateStatusChanged Handlers to initialize changes in state.
        /// </summary>
        public void MoveToNextState(IDialogState nextState)
        {
            
            if(StateCompleted!= null)
            {
                StateCompleted(_curState, new System.EventArgs());
            }
            _curState = nextState;
            System.Diagnostics.Debug.WriteLine("State changed to " +_curState.Type.ToString());
            Clock.Start();
        }
         public void MoveToNextState(DialogStateType type)
        {
            
            if(StateCompleted!= null)
            {
                StateCompleted(_curState, new System.EventArgs());
            }
            _curState = StateCreator(type);
            System.Diagnostics.Debug.WriteLine(_curState.Type.ToString());
            Clock.Start();
        }
   
        //public void RecoObject_CommandRecognized(object sender, Speech.EventArgs.CommandRecognizedEventArgs args)
        //{
        //    switch (args.Action)
        //    {
        //        case "Get":
        //            if (args.Direction != "NONE")
        //            {
        //                //synthesisEngine.Speak(" Moving toward something");
        //                sysSpeak.Speak(" Moving toward something");
        //            }
        //            break;
        //        case "Hello":
        //            sysSpeak.Speak("Good day! My name is Mary, nice to meet you. Would you like to know more about what I can do?");
        //            break;
        //        case "Help":
        //            sysSpeak.Speak("I can understand objects name, find and bring them back to you. I only know a few objects as followed: block, can.");
        //            break;
        //        case "Stop":
        //            sysSpeak.Speak("System aborting. Please advise when to restart");
        //            break;
        //        case "Pause":
        //            sysSpeak.Speak("System pausing! Please tell me when to resume.");
        //            break;
        //        default:
        //            break;

        //    }
        //}

        public void RecoObject_CommandRecognized(object sender, Speech.EventArgs.CommandRecognizedEventArgs args)
        {
            if (_curState.IsReady)
            {
                StateStatusArgs_Resolver(_curState.VoiceCommandResponse(args.Action));
            }
        }

        public void RecoObject_CommandRecognized_Dictionary(object sender, Speech.EventArgs.CommandRecognized_Dictionary_EventArgs args)
        {
            if (_curState.IsReady)
            {
                StateStatusArgs_Resolver(_curState.VoiceCommandResponse(args.recognizedText));
            }
        }

        private void StateStatusArgs_Resolver(EventArgs.StateStatusEventArgs args)
        {
            if (StateStatusChanged != null)
            {
                StateStatusChanged(_curState, args);
            }

            if (args.ToSpeak != null)
            {
                //sysSpeak.SpeakAsync(args.ToSpeak);
                SpeakText(args.ToSpeak);
            }
            if (args.Type == EventArgs.StateStatusEventTypes.ACTION_REQUESTED)
            {
                var actionEvent = new EventArgs.SpeechActionRequestedEventArgs();
                actionEvent.command = DynamicControl.ControlCommandResolver.TextToCommand(args.ActionRequested);
                actionEvent.actionObject = args.ObjectName;
                if (actionEvent.command != DynamicControl.ControlCommands.NULL)
                {
                    if (SpeechActionRequested != null)
                    {
                        SpeechActionRequested(_curState, actionEvent);
                    }
                    
                }
                else
                {
                    throw new Exception("Command is Null when action requested");
                }
                
            }

            if (args.nextState != null)
            {
                MoveToNextState(args.nextState);
            }
        }
        public static IDialogState StateCreator(Dialog.DialogStateType type)
        {
            switch (type)
            {
                case DialogStateType.SessionAwaitingCommandDialogState:
                    return new States.SessionAwaitingCommandDialogState();
                case DialogStateType.QueryDialogState:
                    return new States.QueryDialogState();
                case DialogStateType.Action_In_Progress:
                    return new States.ActionInProgressDialogState();
                case DialogStateType.IdleDialogState:
                default:
                    return new States.IdleDialogState();
            }
        }
        private void SpeakText(string _text)
        {
            sysSpeak.SpeakAsync(_text);

        }
        public void RobotStatusUpdate_EventHandler(object sender, DynamicControl.RobotStatusUpdateEventArgs args)
        {
            if (args.status != null)
            {
                //sysSpeak.Speak(args.status);
                SpeakText(args.status);
            }
                
        }
    }
}
